using BepuPhysics.Collidables;
using BepuPhysics.Trees;
using BepuUtilities.Memory;
using System;
using System.Runtime.CompilerServices;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif

namespace BepuPhysics.CollisionDetection
{
    public interface IBroadPhaseRayTester
    {
        unsafe void RayTest(CollidableReference collidable, RayData* rayData, float* maximumT);
    }
    public interface IBroadPhaseBatchedRayTester : IBroadPhaseRayTester
    {
        void RayTest(CollidableReference collidable, ref RaySource rays);
    }

    /// <summary>
    /// 使用自定义叶部测试仪帮助测试宽相的活动树和静电树。
    /// </summary>
    /// <typeparam name="TRayTester">用于针对树叶测试射线的类型。</typeparam>
    public struct BroadPhaseRayBatcher<TRayTester> : IDisposable where TRayTester : struct, IBroadPhaseBatchedRayTester
    {
        BroadPhase broadPhase;
        RayBatcher batcher;

        struct LeafTester : IBatchedRayLeafTester
        {
            public TRayTester RayTester;
            public Buffer<CollidableReference> Leaves;

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public void RayTest(int leafIndex, ref RaySource rays)
            {
                RayTester.RayTest(Leaves[leafIndex], ref rays);
            }

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public unsafe void TestLeaf(int leafIndex, RayData* rayData, float* maximumT)
            {
                RayTester.RayTest(Leaves[leafIndex], rayData, maximumT);
            }
        }

        LeafTester activeTester;
        LeafTester staticTester;

        /// <summary>
        /// 构造宽相位的光线批处理程序并初始化其支持资源。
        /// </summary>
        /// <param name="pool">要从中提取资源的池。</param>
        /// <param name="rayTester">用于测试宽相位树遍历发现的叶子的光线测试器。</param>
        /// <param name="batcherRayCapacity">每次遍历中要执行的最大光线数。
        /// 通常应选择该值作为最高值,以避免将数据溢出出二级缓存。</param>
        public BroadPhaseRayBatcher(BufferPool pool, BroadPhase broadPhase, TRayTester rayTester, int batcherRayCapacity = 2048)
        {
            activeTester = new LeafTester { Leaves = broadPhase.activeLeaves, RayTester = rayTester };
            staticTester = new LeafTester { Leaves = broadPhase.staticLeaves, RayTester = rayTester };
            this.broadPhase = broadPhase;
            batcher = new RayBatcher(pool, batcherRayCapacity,
                Math.Max(8, 2 * SpanHelper.GetContainingPowerOf2(Math.Max(broadPhase.StaticTree.LeafCount, broadPhase.ActiveTree.LeafCount))));
        }

        /// <summary>
        /// 将光线添加到批处理程序以对照宽阔的相位树进行测试。
        /// 如果底层光线批处理达到其最大容量,则所有累积的光线将针对宽相位树进行测试,并且累加器将被重置。
        /// </summary>
        /// <param name="Origin">要针对树进行测试的射线的原点。</param>
        /// <param name="direction">要针对树进行测试的光线方向。</param>
        /// <param name="maxumT">射线将行进的最大距离(以射线长度为单位)。</param>
        /// 光线的<param name="id">标识符值。叶测试将有权访问ID。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Add(ref Vector3 origin, ref Vector3 direction, float maximumT, int id = 0)
        {
            if (batcher.Add(ref origin, ref direction, maximumT, id))
            {
                // TODO：请注意,此顺序意味着我们先测试活动树,然后再测试静电树。这一点应该重新考虑-在许多模拟中,
                // 首先测试静电树会更好,因为它的最大T值更为保守。目前还不清楚哪个案件占主导地位。
                batcher.TestRays(ref broadPhase.ActiveTree, ref activeTester);
                batcher.TestRays(ref broadPhase.StaticTree, ref staticTester);
                batcher.ResetRays();
            }
        }

        /// <summary>
        /// 针对宽幅相位树测试所有累积的光线,然后重置批处理程序。
        /// </summary>
        public void Flush()
        {
            if (batcher.RayCount > 0)
            {
                // TODO：类似于此处的添加订单问题,以提高性能。需要测试以确定哪个顺序往往更好。
                batcher.TestRays(ref broadPhase.ActiveTree, ref activeTester);
                batcher.TestRays(ref broadPhase.StaticTree, ref staticTester);
                batcher.ResetRays();
            }
        }

        /// <summary>
        /// 释放基础批处理程序资源。
        /// </summary>
        public void Dispose()
        {
            batcher.Dispose();
        }
    }

    /// <summary>
    /// 根据模拟测试批光线。
    /// </summary>
    /// <typeparam name="TRayHitHandler">用于处理模拟中对象命中的类型。</typeparam>
    public struct SimulationRayBatcher<TRayHitHandler> : IDisposable where TRayHitHandler : struct, IRayHitHandler
    {
        struct Dispatcher : IBroadPhaseBatchedRayTester
        {
            public Simulation Simulation;
            public ShapeHitHandler HitHandler;

            public struct ShapeHitHandler : IShapeRayHitHandler
            {
                public TRayHitHandler HitHandler;
                public CollidableReference Reference;
                public RaySource RaySource;

                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                public bool AllowTest(int childIndex)
                {
                    return HitHandler.AllowTest(Reference, childIndex);
                }

                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                public unsafe void OnRayHit(in RayData ray, ref float maximumT, float t, in Vector3 normal, int childIndex)
                {
                    HitHandler.OnRayHit(ray, ref maximumT, t, normal, Reference, childIndex);
                }
            }


            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public unsafe void RayTest(CollidableReference reference, ref RaySource rays)
            {
                if (HitHandler.HitHandler.AllowTest(reference))
                {
                    Simulation.GetPoseAndShape(reference, out var pose, out var shape);
                    HitHandler.Reference = reference;
                    HitHandler.RaySource = rays;
                    Simulation.Shapes[shape.Type].RayTest(shape.Index, *pose, ref rays, ref HitHandler);
                }
            }

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public unsafe void RayTest(CollidableReference reference, RayData* rayData, float* maximumT)
            {
                if (HitHandler.HitHandler.AllowTest(reference))
                {
                    Simulation.GetPoseAndShape(reference, out var pose, out var shape);
                    Simulation.Shapes[shape.Type].RayTest(shape.Index, *pose, *rayData, ref *maximumT, ref HitHandler);
                }
            }

        }

        BroadPhaseRayBatcher<Dispatcher> batcher;

        public SimulationRayBatcher(BufferPool pool, Simulation simulation, TRayHitHandler hitHandler, int batcherRayCapacity = 2048)
        {
            Dispatcher dispatcher = default;
            dispatcher.Simulation = simulation;
            dispatcher.HitHandler.HitHandler = hitHandler;
            batcher = new BroadPhaseRayBatcher<Dispatcher>(pool, simulation.BroadPhase, dispatcher, batcherRayCapacity);
        }

        /// <summary>
        /// 将光线添加到批处理程序以对照模拟进行测试。
        /// 如果基础光线批处理达到其最大容量,则将根据模拟测试所有累积的光线,并且将重置累加器。
        /// </summary>
        /// <param name="Origin">要针对模拟进行测试的光线的原点。</param>
        /// <param name="direction">要针对模拟进行测试的光线方向。</param>
        /// <param name="maxumT">射线将行进的最大距离(以射线长度为单位)。</param>
        /// 光线的<param name="id">标识符值。回调将有权访问ID。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Add(ref Vector3 origin, ref Vector3 direction, float maximumT, int id = 0)
        {
            batcher.Add(ref origin, ref direction, maximumT, id);
        }

        /// <summary>
        /// 针对宽幅相位树测试所有累积的光线,然后重置批处理程序。
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Flush()
        {
            batcher.Flush();
        }

        public void Dispose()
        {
            batcher.Dispose();
        }
    }
}
